﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.Text;
using T.ServiceComponent.I18N.Service;

namespace T.FAS.Runtime.Base.Entity
{
    public class FASContext : DynamicObject, ICloneable
    {
        Dictionary<string, object> _properties;
        DataRow row;
        private const string CurrentRecordName = "CurrentRecordName";
        public int Count
        {
            get
            {
                return _properties.Count;
            }
        }

        public TRecord CurrentRecord
        {
            get;
            set;
        }

        public List<TRecord> CurrentRecordList
        {
            get;
            set;
        }

        public string PKColumnName
        {
            get;
            set;
        }

        public FASContext()
        {
            _properties = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        }

        public FASContext(Dictionary<string, object> properties): this()
        {
            if (properties != null)
                _properties = new Dictionary<string, object>(properties, StringComparer.OrdinalIgnoreCase);
        }

        public FASContext(DataRow row): this()
        {
            this.row = row;
        }

        public static FASContext BuildRecord(JObject data)
        {
            if (data == null)
                return null;
            Dictionary<string, object> pairs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            foreach (var item in data.Properties())
            {
                if (item.Value == default(JToken))
                {
                    pairs.Add(item.Name, item.Value);
                }
                else
                {
                    if (item.Value.Type == JTokenType.Object)
                    {
                        pairs.Add(item.Name, BuildRecord(item.Value as JObject));
                    }
                    else if (item.Value.Type == JTokenType.Array)
                    {
                        List<FASContext> records = new List<FASContext>();
                        foreach (var aItem in item.Value as JArray)
                        {
                            records.Add(BuildRecord(aItem as JObject));
                        }

                        pairs.Add(item.Name, records);
                    }
                    else
                    {
                        if (item.Value.Type == JTokenType.Boolean)
                            pairs.Add(item.Name, Convert.ToBoolean(item.Value) ? 1 : 0);
                        else
                            pairs.Add(item.Name, item.Value);
                    }
                }
            }

            return new FASContext(pairs);
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _properties.Keys;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            string name = binder.Name.ToLower();
            if (name.Equals(CurrentRecordName.ToLower()))
            {
                throw new FasException(BaseExceptionCode.FASContextError, $"{TermService.Current.GetText("T_FAS_fasr_Base_1997920639", $"CurrentRecord为FASContext的系统预留属性，请更换")}");
            }

            if (_properties.ContainsKey(name))
            {
                _properties[name] = value;
                return true;
            }
            else
            {
                return false;
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            string name = binder.Name.ToLower();
            if (_properties.ContainsKey(name))
            {
                result = _properties[name];
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        public object GetValue(string propertyName)
        {
            if (_properties != null && _properties.ContainsKey(propertyName.ToLower()))
            {
                return _properties[propertyName.ToLower()];
            }

            return null;
        }

        public bool IsContainProperty(string propertyName)
        {
            if (_properties != null && _properties.ContainsKey(propertyName.ToLower()))
            {
                return true;
            }

            return false;
        }

        public void SetValue(string propertyName, object dataValue)
        {
            if (propertyName.Equals(CurrentRecordName.ToLower()))
            {
                throw new FasException(BaseExceptionCode.FASContextError, $"{TermService.Current.GetText("T_FAS_fasr_Base_1997920639", $"CurrentRecord为FASContext的系统预留属性，请更换")}");
            }

            if (_properties.ContainsKey(propertyName))
                _properties[propertyName] = dataValue;
            else
                _properties.Add(propertyName, dataValue);
        }

        public object Clone()
        {
            Dictionary<string, object> newObj = new Dictionary<string, object>(this._properties);
            if (!string.IsNullOrEmpty(PKColumnName) && newObj.ContainsKey(PKColumnName))
            {
                var obj = newObj[PKColumnName];
                if (obj is string)
                {
                    newObj[PKColumnName] = Guid.NewGuid().ToString();
                }
                else if (obj is int)
                {
                    newObj[PKColumnName] = DateTime.Now.GetHashCode();
                }
                else if (obj is long)
                {
                    newObj[PKColumnName] = DateTime.Now.GetHashCode();
                }
                else
                    newObj.Remove(PKColumnName);
            }

            return new TRecord(newObj)
            {PKColumnName = this.PKColumnName};
        }

        public object this[string name]
        {
            get
            {
                if (_properties != null && _properties.ContainsKey(name.ToLower()))
                {
                    return _properties[name.ToLower()];
                }

                return null;
            }

            set
            {
                SetValue(name.ToLower(), value);
            }
        }
    }
}